#include "httpconn.h"
bool HttpConn::isET = true;

std::atomic<int> HttpConn::userCount;
const char *HttpConn::srcDir;

HttpConn::HttpConn() : fd_(-1), isClose_(true), iovCnt_(0)
{
    addr_ = {0};
}

HttpConn::~HttpConn()
{
    Close();
}

void HttpConn::Close()
{
    response_.UnmapFile();
    if (isClose_ == false)
    {
        isClose_ = true;
        userCount--;
        LOG_INFO("Client: [%d] (%s : %d) quit, UserCount:%d", fd_, GetIP(), GetPort(), (int)userCount);
        Log::Instance()->flush();
        close(fd_);
    }
}

void HttpConn::init(int sockFd, const sockaddr_in &addr)
{
    assert(sockFd >= 0);
    fd_ = sockFd;
    addr_ = addr;
    readBuff_.ClearBuffer();
    writeBuff_.ClearBuffer();
    userCount++;
    isClose_ = false;
    LOG_INFO("Client: [%d] (%s : %d) in, userCount:%d", fd_, GetIP(), GetPort(), (int)userCount);
}

ssize_t HttpConn::read(int *saveErrno)
{
    ssize_t len = -1;
    do
    {
        len = readBuff_.ReadFd(fd_, saveErrno);
        if (len <= 0)
            break;
    } while (isET);
    return len;
}

ssize_t HttpConn::write(int *saveErrno)
{
    ssize_t len = -1;
    do
    {
        len = writev(fd_, iov_, iovCnt_);
        if (len <= 0)
        {
            *saveErrno = errno;
            break;
        }
        if (static_cast<size_t>(len) > iov_[0].iov_len)
        {
            iov_[1].iov_base = (uint8_t *)iov_[1].iov_base + (static_cast<size_t>(len) - iov_[0].iov_len);
            iov_[1].iov_len -= len - iov_[0].iov_len;
            if (iov_[0].iov_len)
            {
                writeBuff_.ClearBuffer();
                iov_[0].iov_len = 0;
            }
        }
        else
        {
            iov_[0].iov_base = (uint8_t *)iov_[0].iov_base + len;
            iov_[0].iov_len -= len;
            writeBuff_.HasReaded(len);
        }

    } while ((isET || ToWriteBytes() > 10240));
    return len;
}

bool HttpConn::process()
{
    request_.Init();
    if (request_.parse(readBuff_))
    {
        response_.Init(srcDir, request_.path(), request_.IsKeepAlive(), 200);
    }
    else
    {
        response_.Init(srcDir, request_.path(), false, 400);
    }
    response_.MakeResponse(writeBuff_);

    iov_[0].iov_base = const_cast<char *>(writeBuff_.Peek());
    iov_[0].iov_len = writeBuff_.ReadAble();
    iovCnt_ = 1;

    if (response_.FileLen() > 0 && response_.File())
    {
        iov_[1].iov_base = response_.File();
        iov_[1].iov_len = response_.FileLen();
        iovCnt_ = 2;
    }
    return true;
}

int HttpConn::GetFd() const
{
    return fd_;
}

int HttpConn::GetPort() const
{
    return addr_.sin_port;
}

const char *HttpConn::GetIP() const
{
    return inet_ntoa(addr_.sin_addr);
}

sockaddr_in HttpConn::GetAddr() const
{
    return addr_;
}